/*******************************************************************************
 * Copyright (c) 2009 Siemens AG
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Kai Toedter - initial API and implementation
 *******************************************************************************/

package com.thomsonreuters.ce.edps.ui.views.treeview;

import java.awt.Color;
import java.util.Enumeration;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thomsonreuters.ce.base.application.service.ISelectionService;
import com.thomsonreuters.ce.base.application.service.IViewContribution;
import com.thomsonreuters.ce.edps.model.IPerson;
import com.thomsonreuters.ce.edps.model.IPersonListener;
import com.thomsonreuters.ce.edps.model.IPersonManager;
import com.thomsonreuters.ce.edps.model.event.PersonEvent;

public class TreeView implements IViewContribution, IPersonListener {
	protected Logger logger = LoggerFactory.getLogger(TreeView.class);

	protected ImageIcon icon;
	protected JComponent view;
	protected IPersonManager personManager;
	protected ISelectionService selectionService;

	protected JTree tree;
	protected DefaultMutableTreeNode top;

	public TreeView() {
		Runnable uiCreator = new Runnable() {
			public void run() {
				icon = new ImageIcon(this.getClass().getResource(
						"/icons/folder.png"));
				top = new DefaultMutableTreeNode("Persons");

				tree = new JTree(top);
				view = new JScrollPane(tree);
				view.setBorder(BorderFactory.createCompoundBorder(BorderFactory
						.createEmptyBorder(2, 2, 2, 2), BorderFactory
						.createLineBorder(Color.lightGray)));

				ImageIcon folderIcon = new ImageIcon(this.getClass()
						.getResource("/icons/folder.png"));
				ImageIcon leafIcon = new ImageIcon(this.getClass().getResource(
						"/icons/user.png"));
				if (leafIcon != null) {
					DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
					renderer.setLeafIcon(leafIcon);
					renderer.setOpenIcon(folderIcon);
					renderer.setClosedIcon(folderIcon);
					tree.setCellRenderer(renderer);
				}

				tree.addTreeSelectionListener(new TreeSelectionListener() {
					public void valueChanged(TreeSelectionEvent e) {
						DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree
								.getLastSelectedPathComponent();
						if (node != null) {
							Object object = node.getUserObject();
							if (selectionService != null) {
								selectionService.objectSelected(object);
							}
						}
					}
				});
			}
		};
		SwingUtilities.invokeLater(uiCreator);
	}

	private void createNodes(DefaultMutableTreeNode top) {
		List<IPerson> persons = personManager.getPersons();

		for (IPerson person : persons) {
			boolean companyFound = false;
			DefaultMutableTreeNode companyNode = null;
			for (int i = 0; i < top.getChildCount(); i++) {
				companyNode = (DefaultMutableTreeNode) top.getChildAt(i);
				if (companyNode.getUserObject().toString().equals(
						person.getCompany())) {
					companyFound = true;
					break;
				}
			}
			if (!companyFound) {
				companyNode = new DefaultMutableTreeNode(person.getCompany());
				top.add(companyNode);
			}
			companyNode.add(new DefaultMutableTreeNode(person));
		}
	}

	@Override
	public Icon getIcon() {
		return icon;
	}

	@Override
	public String getName() {
		return "Tree View";
	}

	@Override
	public JComponent getView() {
		return view;
	}

	@Override
	public int getPosition() {
		return 1;
	}

	public synchronized void removeSelectionService(
			ISelectionService selectionService) {
		this.selectionService = null;
	}

	public synchronized void setSelectionService(
			ISelectionService selectionService) {
		this.selectionService = selectionService;
	}

	public void removePersonManager(final IPersonManager personManager) {

		final TreeView treeView = this;
		Runnable uiCreator = new Runnable() {
			public void run() {
				logger.info("removePersonManager");
				if (treeView.personManager == personManager) {
					treeView.personManager = null;
					top.removeAllChildren();
					((DefaultTreeModel) tree.getModel()).reload(top);
				}
				;
			}
		};

		SwingUtilities.invokeLater(uiCreator);
	}

	public void setPersonManager(final IPersonManager personManager) {
		final TreeView treeView = this;
		Runnable uiCreator = new Runnable() {
			public void run() {
				logger.info("set personManager: " + personManager);
				treeView.personManager = personManager;
				top.removeAllChildren();
				createNodes(top);
				((DefaultTreeModel) tree.getModel()).reload(top);
				expand(new TreePath(top));
			}
		};

		SwingUtilities.invokeLater(uiCreator);

	}

	@Override
	public void handleEvent(PersonEvent event) {
		if (event.getType() == PersonEvent.Type.DELETE) {
			DefaultMutableTreeNode node = searchNode(event.getPerson());
			if (node == null) {
				return;
			}

			DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) (node
					.getParent());
			if (parentNode == null) {
				return;
			}

			parentNode.remove(node);
			if (parentNode.getChildCount() == 0) {
				// delete company if there
				// are no persons anymore
				top.remove(parentNode);
				((DefaultTreeModel) tree.getModel()).reload(top);
			} else {
				((DefaultTreeModel) tree.getModel()).reload(parentNode);
			}
		}
	}

	@SuppressWarnings("unchecked")
	public DefaultMutableTreeNode searchNode(Object userObject) {
		DefaultMutableTreeNode node = null;
		Enumeration nodes = top.breadthFirstEnumeration();

		while (nodes.hasMoreElements()) {
			node = (DefaultMutableTreeNode) nodes.nextElement();
			if (userObject == node.getUserObject()) {
				return node;
			}
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	private void expand(TreePath parent) {
		TreeNode node = (TreeNode) parent.getLastPathComponent();
		if (node.getChildCount() >= 0) {
			for (Enumeration e = node.children(); e.hasMoreElements();) {
				TreeNode n = (TreeNode) e.nextElement();
				TreePath path = parent.pathByAddingChild(n);
				expand(path);
			}
		}
		tree.expandPath(parent);
	}
}
